home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
cmds
/
dump
/
RCS
/
main.c,v
< prev
Wrap
Text File
|
1992-03-28
|
60KB
|
2,767 lines
head 1.12;
branch ;
access ;
symbols ;
locks ; strict;
comment @ * @;
1.12
date 92.03.28.17.29.31; author kupfer; state Exp;
branches ;
next 1.11;
1.11
date 92.03.28.11.54.54; author jhh; state Exp;
branches ;
next 1.10;
1.10
date 91.11.22.15.02.14; author jhh; state Exp;
branches ;
next 1.9;
1.9
date 91.11.22.14.09.03; author jhh; state Exp;
branches ;
next 1.8;
1.8
date 91.10.11.11.57.18; author jhh; state Exp;
branches ;
next 1.7;
1.7
date 91.09.10.11.16.59; author jhh; state Exp;
branches ;
next 1.6;
1.6
date 91.06.28.12.27.23; author shirriff; state Exp;
branches ;
next 1.5;
1.5
date 91.06.05.15.06.58; author mgbaker; state Exp;
branches ;
next 1.4;
1.4
date 91.05.10.17.00.37; author mgbaker; state Exp;
branches ;
next 1.3;
1.3
date 90.11.15.01.21.03; author rab; state Exp;
branches ;
next 1.2;
1.2
date 90.10.07.15.10.39; author rab; state Exp;
branches ;
next 1.1;
1.1
date 90.09.07.11.47.34; author rab; state Exp;
branches ;
next ;
desc
@@
1.12
log
@Use -L flag so that tar will save long names. Lint.
@
text
@/*
* main.c --
*
* Main routine for the sprite dump program.
*
*
* Copyright 1988 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.11 92/03/28 11:54:54 jhh Exp Locker: kupfer $";
#endif
#include <sprite.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <option.h>
#include <fs.h>
#include <dev/tape.h>
#include <status.h>
#include <cfuncproto.h>
#include <varargs.h>
#include <assert.h>
#include <dev/exabyte.h>
#include <bstring.h>
#include <sys/errno.h>
#define DEBUG
#ifdef DEBUG
#define debugp(x) ((void) fprintf x, fflush(stderr))
#else
#define debugp(x)
#endif
#define SPRITE_OLD_DUMP_HEADER "SPRITE DUMP TAPE #"
#define SPRITE_DUMP_HEADER "SPRITE DUMP TAPE,"
#define SPRITE_DUMP_INFO " Version %d Level %d Tape %d"
#define SPRITE_DUMP_VERSION 1
#define DUMPDATES "/sprite/admin/dump/dumpdates"
#define LOGFILE "/sprite/admin/dump/dumplog"
#define DRIVELOG "/sprite/admin/dump/statuslog"
#define TAR "tar.gnu"
#define KBytes(n) (n * 1024)
#define MBytes(n) (1024 * KBytes(n))
#define IOBUF_SIZE KBytes(62) /* Exebyte likes 62KB chunks */
#define TOC_SIZE_OLD MBytes(10) /* TOC occupied 10 MB on the tape */
#define TOC_USEABLE_OLD MBytes(2) /* About 2 MB of it can be used */
#define TOC_SIZE KBytes(16) /* No longer needs to be big. */
#define TOC_USEABLE TOC_SIZE /* and we can use it all */
#define TAR_BLOCK_SIZE KBytes(64) /* Do the tar in 64K blocks. */
#define LABEL_SIZE_OLD IOBUF_SIZE /* Size of useable label. */
#define LABEL_SIZE TOC_SIZE /* Size of useable label. */
static char tapeBuffer[IOBUF_SIZE];
static char *directoryToDump;
static tarChild;
static int pipefd[2];
static int archivefd;
static int dumpLevel = 0;
static int tapeNumber;
static int tapeLevel;
static int fileNumber;
static int verbose;
static char *archiveFileName;
static char *mailWho;
static time_t lastTime;
static time_t startTime;
static int fatalErrors;
static int nonFatalErrors;
static int archiveFileIsATapeDrive;
static int printTOC;
static int progArgc;
static char **progArgv;
static int reInitialize = 0;
static int reInitializeSafe = 0;
static long totalBytes;
static int debug;
static int oldFormat;
static int tarBlocks;
static int tapePosition = 0;
static int version = 0;
static int labelSize = 0;
static int lastFile;
static int official = 1;
#ifdef PROG_RESTORE
static int printContents = 0;
#endif
#ifdef PROG_DUMP
static int resetAccessTimes;
static Option OptionArray[] = {
{ OPT_TRUE, "a", (char *) &resetAccessTimes, "Reset access times" },
{ OPT_TRUE, "d", (char *) &debug, "Debug" },
{ OPT_STRING, "f", (char *) &archiveFileName, "Name of archive file" },
{ OPT_INT, "i", (char *) &tapeNumber, "Initialize the tape" },
{ OPT_INT, "l", (char *) &dumpLevel, "Dump level (0-9)" },
{ OPT_STRING, "m", (char *) &mailWho, "Send mail upon completion" },
{ OPT_TRUE, "r", (char *) &reInitialize, "Re-initialize the tape" },
{ OPT_TRUE, "s", (char *) &reInitializeSafe, "Safely re-initialize tape" },
{ OPT_TRUE, "t", (char *) &printTOC, "Print table of contents" },
{ OPT_TRUE, "v", (char *) &verbose, "Verbose" },
{ OPT_FALSE, "u", (char *) &official, "Unofficial dump" },
};
#endif
#ifdef PROG_RESTORE
static int relativePaths;
static Option OptionArray[] = {
{ OPT_STRING, "f", (char *) &archiveFileName, "Name of archive" },
{ OPT_TRUE, "d", (char *) &debug, "Debug" },
{ OPT_INT, "n", (char *) &fileNumber, "File number to use" },
{ OPT_TRUE, "r", (char *) &relativePaths, "Use relative pathnames" },
{ OPT_TRUE, "t", (char *) &printTOC, "Print table of contents" },
{ OPT_TRUE, "v", (char *) &verbose, "Verbose" },
{ OPT_TRUE, "T", (char *) &printContents, "Print contents of dump file"},
};
#endif
static void cleanup_sighup _ARGS_((int sig));
static void cleanup_sigint _ARGS_((int sig));
static void cleanup_sigquit _ARGS_((int sig));
static void cleanup_sigpipe _ARGS_((int sig));
static void cleanup_sigterm _ARGS_((int sig));
static void openArchiveFile _ARGS_((void));
static void forkOffTar _ARGS_((void));
static void dumpDirectory _ARGS_((char *dir));
static void initializeTape _ARGS_((void));
static void sendMail _ARGS_((const char *msg));
static void rewindTape _ARGS_((void));
static void fatal _ARGS_((char *fmt, ...));
static void warning _ARGS_((char *fmt, ...));
static void readTapeLabel _ARGS_((void));
static void rewindTape _ARGS_((void));
static void openLog _ARGS_((void));
static void skipOverFiles _ARGS_((void));
#ifdef PROG_RESTORE
static void findLastFile _ARGS_((void));
#endif
static void waitForChildToDie _ARGS_((void));
static void setFileNumber _ARGS_((void));
static void quote_string _ARGS_((char *to, const char *from));
static void checkTape _ARGS_((void));
static int parseDumpInfo _ARGS_((char *buf));
static void gotoEOD _ARGS_((void));
static ReturnStatus skipFiles _ARGS_((int num));
#ifdef PROG_DUMP
static int getNextDumpDateEntry _ARGS_((void));
static void writeTapeLabel _ARGS_((void));
static void flushOutput _ARGS_((void));
static void getDumpDate _ARGS_((void));
static void recordTime _ARGS_((void));
#endif
#ifdef __STDC__
#define VOID void
#endif
void
main(argc, argv)
int argc;
char **argv;
{
uid_t root;
uid_t dumper;
struct passwd *pwPtr;
uid_t euid;
extern uid_t geteuid();
extern int setreuid();
#ifdef PROG_DUMP
ReturnStatus status;
#endif
char *date;
int i;
signal(SIGHUP, cleanup_sighup);
signal(SIGINT, cleanup_sigint);
signal(SIGQUIT, cleanup_sigquit);
signal(SIGPIPE, cleanup_sigpipe);
signal(SIGTERM, cleanup_sigterm);
startTime = time(0L);
date = asctime(localtime(&startTime));
date[24] = '\0';
debugp((stderr, "\n"));
for (i = 0; i < argc; i++) {
debugp((stderr, "%s ", argv[i]));
}
debugp((stderr, "\n"));
debugp((stderr, "%s\n", date));
argc = Opt_Parse(argc, argv, OptionArray, Opt_Number(OptionArray), 0);
progArgc = argc;
progArgv = argv;
pwPtr = getpwnam("root");
if (pwPtr != (struct passwd *) 0) {
root = pwPtr->pw_uid;
pwPtr = getpwnam("dumper");
if (pwPtr != (struct passwd *) 0) {
dumper = pwPtr->pw_uid;
euid = geteuid();
if (euid == root && setreuid(dumper, -1) != 0) {
perror("Couldn't set real userID to dumper");
exit(1);
}
}
}
endpwent();
if ((TAR_BLOCK_SIZE & (512 - 1)) != 0) {
fatal("Tar block size must be multiple of 512\n");
}
tarBlocks = TAR_BLOCK_SIZE / 512;
oldFormat = 0;
openLog();
if (archiveFileName == NULL) {
fatal("No archive file specified");
}
tapeLevel = dumpLevel;
if (tapeNumber != 0) {
openArchiveFile();
initializeTape();
close(archivefd);
if (argc < 2) {
exit(EXIT_SUCCESS);
}
}
openArchiveFile();
if (archiveFileIsATapeDrive) {
readTapeLabel();
if (reInitialize || reInitializeSafe) {
if (reInitializeSafe) {
checkTape();
}
initializeTape();
close(archivefd);
if (argc < 2) {
exit(EXIT_SUCCESS);
}
openArchiveFile();
}
}
if (printTOC) {
if (!archiveFileIsATapeDrive) {
fatal("Cannot print TOC: Archive is not a tapeDrive");
}
fprintf(stderr, "%s\n", tapeBuffer);
if (argc < 2) {
exit(EXIT_SUCCESS);
}
}
if (argc < 2) {
Opt_PrintUsage(argv[0], OptionArray, Opt_Number(OptionArray));
exit(EXIT_FAILURE);
}
#ifdef PROG_DUMP
directoryToDump = argv[1];
debugp((stderr, "dumping %s\n", directoryToDump));
if (archiveFileIsATapeDrive) {
setFileNumber();
if (oldFormat) {
skipOverFiles();
} else {
/*
* We are currently at the end of the label since we just read
* it. The tar file will follow the subsequent file mark.
*/
status = skipFiles(1);
if (status != SUCCESS) {
fatal("Can't skip over last filemark\n");
}
}
}
getDumpDate();
forkOffTar();
dumpDirectory(directoryToDump);
flushOutput();
waitForChildToDie();
openArchiveFile();
if (fatalErrors) {
sendMail("Dump failed with fatal errors");
} else {
if (nonFatalErrors) {
sendMail("Dump completed with non-fatal errors.");
} else {
sendMail("Dump completed successfully.");
}
recordTime();
}
debugp((stderr, "finished dumping %s, %.1lf MBytes\n",
directoryToDump, (double) totalBytes / (double) MBytes(1)));
#else /* PROG_DUMP */
assert(progArgc >= 2);
if (fileNumber == 0) {
setFileNumber();
} else {
findLastFile();
}
skipOverFiles();
forkOffTar();
waitForChildToDie();
openArchiveFile();
rewindTape();
#endif /* PROG_DUMP */
debugp((stderr,
"%s exiting, there were %d non-fatal errors, %d hard errors\n",
argv[0], nonFatalErrors, fatalErrors));
exit(fatalErrors);
}
/*
*----------------------------------------------------------------------
*
* dumpDirectory --
*
* Procedure to dump a directory tree. This routine does an
* inorder traversal of a directory. It calls itself recursively
* to dump each subdirectory.
*
* Results:
* None.
*
* Side effects:
* Depends on the options, but normally the files in the specified
* directory are dumped.
*
*----------------------------------------------------------------------
*/
static void
dumpDirectory(dir)
char *dir;
{
char pathname[MAXPATHLEN];
char backslash_pathname[MAXPATHLEN];
DIR *dirDesc;
struct direct *d;
int slash;
if ((dirDesc = opendir(dir)) == NULL) {
warning("Cannot open directory `%s'", dir);
++nonFatalErrors;
return;
}
slash = (dir[strlen(dir) - 1] == '/');
while ((d = readdir(dirDesc)) != NULL) {
struct stat statBuf;
if (*d->d_name == '.') {
if (d->d_name[1] == 0)
continue;
if (d->d_name[1] == '.' && d->d_name[2] == 0)
continue;
}
(void) sprintf(pathname, slash ? "%s%s" : "%s/%s", dir, d->d_name);
if (lstat(pathname, &statBuf)) {
warning("can't lstat %s", pathname);
++nonFatalErrors;
continue;
}
quote_string(backslash_pathname, pathname);
if (statBuf.st_mtime >= lastTime || statBuf.st_ctime >= lastTime) {
if (puts(backslash_pathname) == EOF) {
(void) fprintf(stderr, "error in puts\n");
++fatalErrors;
} else if (verbose) {
fprintf(stderr, "dumping %s\n", backslash_pathname);
}
totalBytes += statBuf.st_size;
}
if (((statBuf.st_mode & S_IFDIR) == S_IFDIR) &&
((statBuf.st_mode & S_IFRLNK) != S_IFRLNK) &&
((statBuf.st_mode & S_IFPDEV) != S_IFPDEV)) {
dumpDirectory(pathname);
}
}
(void) closedir(dirDesc);
return;
}
static struct {
int tape;
int file;
int level;
double mbytes;
double remaining;
double errorRate;
time_t time;
char dirname[MAXPATHLEN];
} dumpDateEntry;
#ifdef PROG_DUMP
/*
*----------------------------------------------------------------------
*
* recordTime --
*
* Append the start time of the current dump to the dump database.
*
* Results:
* None.
*
* Side effects:
* The start time of the current dump is appended to the end
* of the dump database. A fatal error occurs if the database
* doesn't exist or is unwritable.
*
*----------------------------------------------------------------------
*/
static void
recordTime()
{
FILE *fp = NULL;
char *date;
Dev_TapeStatus tapeStatus;
int errors;
double mbytes;
double errorRate;
ReturnStatus status = FAILURE;
double remaining;
double mbytesPerBlock;
char *name = "UNKNOWN";
char *serial = "UNKNOWN";
int blocks;
char shortDate[16];
char buf[128];
if (official) {
if ((fp = fopen(DUMPDATES, "a")) == NULL) {
fatal("Can't open %s", DUMPDATES);
}
}
date = asctime(localtime(&startTime));
date[24] = '\0';
mbytes = ((double) totalBytes) / ((double) MBytes(1));
debugp((stderr, "mbytes = %lf\n", mbytes));
errorRate = -1;
remaining = -1;
if (!oldFormat) {
bzero((char *) &tapeStatus, sizeof(tapeStatus));
debugp((stderr, "Getting tape status\n"));
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
if (status == SUCCESS) {
mbytesPerBlock =
(double) tapeStatus.blockSize / (double) MBytes(1);
debugp((stderr, "position = %d, remaining = %d\n",
tapeStatus.position, tapeStatus.remaining));
blocks = tapeStatus.position - tapePosition;
mbytes = blocks * mbytesPerBlock;
errors = tapeStatus.readWriteRetry + tapeStatus.dataError;
errorRate = ((double) errors / (double) blocks) * 100.0;
remaining = tapeStatus.remaining * mbytesPerBlock;
debugp((stderr,
"mbytes = %lf, errorRate = %lf, remaining = %lf\n",
mbytes, errorRate, remaining));
}
}
(void) sprintf(buf, "%03d %03d %d %6.1lf %6.1lf %s %s\n",
tapeNumber, fileNumber, dumpLevel, mbytes, remaining,
date, directoryToDump);
if (archiveFileIsATapeDrive) {
strcat(tapeBuffer, buf);
writeTapeLabel();
if (close(archivefd) != 0) {
fatal("Close of archive failed");
}
}
if (official) {
fprintf(fp, "%s", buf);
(void) fclose(fp);
}
if ((fp = fopen(DRIVELOG, "a")) == NULL) {
fatal("Can't open %s", DRIVELOG);
}
if (status == SUCCESS) {
switch(tapeStatus.type) {
case DEV_TAPE_EXB8200:
name = "EXB-8200";
break;
case DEV_TAPE_EXB8500:
name = "EXB-8500";
break;
case DEV_TAPE_TLZ04:
name = "DEC-TLZ04";
break;
default: {
if (tapeStatus.type & DEV_TAPE_8MM) {
name = "UNKNOWN-8MM";
} else if (tapeStatus.type & DEV_TAPE_4MM) {
name = "UNKNOWN-4MM";
}
}
}
if (tapeStatus.serial[0] != '\0') {
serial = tapeStatus.serial;
}
}
bcopy(&date[4], shortDate, 7);
bcopy(&date[20], &shortDate[7], 4);
shortDate[11] = '\0';
fprintf(fp, "%-10s %-10s %3d %7.1lf %5.1lf%% %s %s\n", name, serial,
tapeNumber, mbytes, errorRate, shortDate, archiveFileName);
(void) fclose(fp);
return;
}
/*
*----------------------------------------------------------------------
*
* getNextDumpDateEntry --
*
* Reads the next entry from the dump database file,
* and puts the information into a structure.
*
* Results:
* Returns non-zero if the next entry is read successfully.
*
* Side effects:
* A fatal error occurs if the database doesn't exist, is unreadable
* or if it is improperly formated.
*
*----------------------------------------------------------------------
*/
static int
getNextDumpDateEntry()
{
static FILE *fp;
static int lineCnt;
char buf[0x1000];
char *s;
if (fp == NULL) {
if ((fp = fopen(DUMPDATES, "r")) == NULL) {
fatal("Can't open %s", DUMPDATES);
}
}
/*
* read in the file line by line until we get a valid entry.
*/
while (fgets(buf, sizeof(buf), fp)) {
++lineCnt;
/*
* If the line is empty, only white space, or is a
* comment, then throw it away and continue.
*/
s = buf;
while (*s == ' ' || *s == '\t') {
++s;
}
if (*s == '#' || *s == '\n' || *s == '\0') {
continue;
}
if (parseDumpInfo(s) == 0) {
fatal("format error in %s: line %d |%s|",
DUMPDATES, lineCnt, buf);
}
return 1;
}
(void) fclose(fp);
return 0;
}
#endif
static int
parseDumpInfo(buf)
char *buf;
{
extern time_t mktime();
static char months[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
struct tm tm;
char *s;
int i;
int n;
int token = 1;
bzero((char *) &dumpDateEntry, sizeof(dumpDateEntry));
/*
* The first token is the tape number
*/
if ((s = strtok(buf, " \t\n")) == NULL || !isdigit(*s)) {
goto mismatch;
}
dumpDateEntry.tape = atoi(s);
token++;
/*
* The next token is the file number
*/
if ((s = strtok(NULL, " \t\n")) == NULL || !isdigit(*s)) {
goto mismatch;
}
dumpDateEntry.file = atoi(s);
token++;
/*
* The next token should be a single digit in the range 0-9 that
* indicates the level of the dump.
*/
s = strtok((char *) NULL, " \t\n");
if (s == NULL || !isdigit(*s) || strlen(s) != 1) {
goto mismatch;
}
dumpDateEntry.level = *s - '0';
token++;
/* the next token should be the number of bytes */
s = strtok((char *) NULL, " \t\n");
if (strchr(s, (int) '.')) {
/* Number of MBytes. */
n = sscanf(s, "%lf", &dumpDateEntry.mbytes);
if (n != 1) {
goto mismatch;
}
token++;
/* Number of remaining MBytes on tape. */
s = strtok((char *) NULL, " \t\n");
n = sscanf(s, "%lf", &dumpDateEntry.remaining);
if (n != 1) {
goto mismatch;
}
token++;
} else {
n = sscanf(s, "%d", &i);
if (n != 1) {
goto mismatch;
}
}
/*
* The time should be formated just like the return string
* from asctime(3). So, parse the string and make sure the
* format is correct.
*/
if ((s = strtok((char *) NULL, " \t")) == NULL) {
goto mismatch;
}
token++;
if ((s = strtok((char *) NULL, " ")) == NULL) {
goto mismatch;
}
token++;
for (i = 13; --i >= 0;) {
if (strcmp(months[i], s) == 0) {
break;
}
}
if ((tm.tm_mon = i) < 0) {
goto mismatch;
}
if ((s = strtok((char *) NULL, " ")) == NULL) {
goto mismatch;
}
token++;
tm.tm_mday = atoi(s);
if ((s = strtok((char *) NULL, ":")) == NULL) {
goto mismatch;
}
token++;
tm.tm_hour = atoi(s);
if ((s = strtok((char *) NULL, ":")) == NULL) {
goto mismatch;
}
token++;
tm.tm_min = atoi(s);
if ((s = strtok((char *) NULL, " ")) == NULL) {
goto mismatch;
}
token++;
tm.tm_sec = atoi(s);
if ((s = strtok((char *) NULL, " \t\n")) == NULL) {
goto mismatch;
}
tm.tm_year = atoi(s) - 1900;
/* Convert to old-fashioned calander time */
if((dumpDateEntry.time = mktime(&tm)) == -1) {
debugp((stderr, "parseDumpInfo: mktime failed\n"));
return 0;
}
token++;
if ((s = strtok((char *) NULL, " \t\n")) == NULL) {
goto mismatch;
}
/*
* The remainder of the line is the directory name.
*/
strcpy(dumpDateEntry.dirname, s);
return 1;
mismatch:
debugp((stderr, "parseDumpInfo: parse error on token %d \"%s\"\n",
token, s));
return 0;
}
#ifdef PROG_DUMP
/*
*----------------------------------------------------------------------
*
* getDumpDate --
*
* Reads the dump database file, and determines the last time
* that a lower level dump of the directory was done.
*
* Results:
* Returns the time of the last lower level dump.
*
* Side effects:
* A fatal error occurs if the database doesn't exist, is unreadable
* or if it is improperly formated.
*
*----------------------------------------------------------------------
*/
static void
getDumpDate()
{
time_t t = 0;
while (getNextDumpDateEntry()) {
if (strcmp(dumpDateEntry.dirname, directoryToDump) != 0) {
continue;
}
if (dumpDateEntry.level < dumpLevel) {
t = dumpDateEntry.time;
}
}
lastTime = t;
return;
}
#endif
/*
*----------------------------------------------------------------------
*
* openArchiveFile --
*
* Opens the archive file and checks to see if it is a tapedrive.
*
* Results:
* None
*
* Side effects:
* Opens the archive file.
*
*----------------------------------------------------------------------
*/
static void
openArchiveFile()
{
struct stat statBuf;
extern int Fs_GetAttributes();
Fs_Attributes attrs;
Dev_TapeStatus tapeStatus;
ReturnStatus status;
debugp((stderr, "opening %s as archive file\n", archiveFileName));
#ifdef PROG_DUMP
if (strcmp(archiveFileName, "-") == 0) {
archivefd = 1;
} else if ((archivefd = open(archiveFileName,O_RDWR)) < 0) {
if ((archivefd = open(archiveFileName,
O_RDWR|O_CREAT, 0664)) < 0) {
fatal("Can't open `%s'", archiveFileName);
}
}
#else
if (strcmp(archiveFileName, "-") == 0) {
archivefd = 0;
} else if ((archivefd = open(archiveFileName,O_RDONLY)) < 0) {
fatal("Can't open `%s'", archiveFileName);
}
#endif
if (fstat(archivefd, &statBuf)) {
fatal("Cannot stat %s", archiveFileName);
}
switch (statBuf.st_mode & S_IFMT) {
case S_IFREG: /* regular file */
break;
case S_IFCHR: /* character dev. -- probably a tape drive */
if (Fs_GetAttributes(archiveFileName, 0, &attrs) != SUCCESS) {
fatal("Cannot get attributes of %s", archiveFileName);
}
if (attrs.devType == 5) {
archiveFileIsATapeDrive = TRUE;
bzero((char *) &tapeStatus, sizeof(tapeStatus));
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
debugp((stderr, "IOC_TAPE_STATUS returned 0x%x\n", status));
if (status != SUCCESS) {
oldFormat = TRUE;
debugp((stderr, "Using old format.\n", status));
} else {
debugp((stderr, "tapeStatus.type is 0x%x\n", tapeStatus.type));
if (tapeStatus.type == DEV_TAPE_EXB8200) {
oldFormat = TRUE;
debugp((stderr, "Using old format.\n", status));
}
#ifndef PROG_DUMP
if ((tapeStatus.type == DEV_TAPE_EXB8500) &&
(tapeStatus.density == DEV_EXB8500_8200_MODE)) {
oldFormat = TRUE;
debugp((stderr, "Using old format.\n", status));
}
#endif
}
break;
}
/* FALLTHROUGH */
default:
warning("%s: not a normal file or tape drive", archiveFileName);
break;
}
return;
}
/*
*----------------------------------------------------------------------
*
* forkOffTar --
*
* Forks off tar and pipes stdout into it.
*
* Results:
* None
*
* Side effects:
* Creates a child process.
*
*----------------------------------------------------------------------
*/
static void
forkOffTar()
{
char tarargs[20];
char blocks[20];
Dev_TapeStatus tapeStatus;
ReturnStatus status;
#ifdef PROG_RESTORE
char **arg;
int i, j;
#endif
if (!oldFormat) {
bzero((char *) &tapeStatus, sizeof(tapeStatus));
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
if (status != SUCCESS) {
debugp((stderr, "IOC_TAPE_STATUS returned 0x%x\n", status));
} else {
tapePosition = tapeStatus.position;
debugp((stderr, "position = %d\n", tapePosition));
}
}
#ifdef PROG_DUMP
if (pipe(pipefd) < 0) {
fatal("Cannot open pipe");
}
switch (tarChild = fork()) {
case -1:
fatal("Can't fork");
case 0:
(void) close(pipefd[1]);
if (dup2(archivefd, 1) < 0) {
fatal("dup2");
}
if (dup2(pipefd[0], 0) < 0) {
fatal("dup2");
}
*tarargs = '\0';
if (resetAccessTimes) {
strcat(tarargs, "a");
}
if (verbose) {
strcat(tarargs, "v");
}
if (debug) {
strcat(tarargs, "e");
}
if (oldFormat) {
strcat(tarargs, "ncfTPL");
debugp((stderr, "execing tar %s - -\n", tarargs));
execlp(TAR, TAR, tarargs, "-", "-", NULL);
} else {
strcat(tarargs, "ncbfTPL");
sprintf(blocks, "%d", tarBlocks);
debugp((stderr, "execing tar %s %s - -\n", tarargs, blocks));
execlp(TAR, TAR, tarargs, blocks, "-", "-", NULL);
}
fatal("exec failed");
default:
(void) close(pipefd[0]);
if (dup2(pipefd[1], 1)) {
fatal("dup2");
}
}
#else
sprintf(blocks, "%d", tarBlocks);
close(archivefd);
switch (tarChild = fork()) {
case -1:
fatal("Can't fork");
case 0: {
char **ptr;
arg = (char **) malloc(sizeof(char **) * (progArgc + 5));
ptr = arg;
*ptr++ = TAR;
if (printContents) {
strcpy(tarargs, "tv");
} else {
strcpy(tarargs, "x");
}
if (oldFormat) {
strcat(tarargs, "pf");
} else {
strcat(tarargs, "pfb");
}
if (verbose) {
strcat(tarargs, "v");
}
if (!relativePaths) {
strcat(tarargs, "P");
}
if (debug) {
strcat(tarargs, "e");
}
*ptr++ = tarargs;
*ptr++ = archiveFileName;
if (!oldFormat) {
*ptr++ = blocks;
}
for (i = 1; (*ptr++ = progArgv[i]) != NULL; ++i) {
continue;
}
debugp((stderr, "execing tar"));
for (j = 0; j < i + 3; j++) {
debugp((stderr, " %s", arg[j]));
}
debugp((stderr, "\n"));
execvp(TAR, arg);
fatal("exec failed");
}
default:
break;
}
#endif
debugp((stderr, "successfully forked tar\n"));
return;
}
#ifdef PROG_DUMP
/*
*----------------------------------------------------------------------
*
* flushOutput --
*
* Wait for tar to finish reading all the data in the pipe.
* Check the error return code.
*
* Results:
* None
*
* Side effects:
* Closes files, increments a global variable.
*
*----------------------------------------------------------------------
*/
static void
flushOutput()
{
debugp((stderr, "flushing output\n"));
(void) fflush(stdout);
(void) close(1);
(void) close(pipefd[1]);
return;
}
#endif
static void
waitForChildToDie()
{
int w;
union wait ws;
while ((w = wait(&ws)) > 0 && w != tarChild) {
continue;
}
switch (ws.w_retcode) {
case 0: /* normal exit */
break;
case 1:
fatal("tar invoked with invalid arguments");
break;
case 2:
warning("tar encountered at least one invalid filename");
++nonFatalErrors;
break;
case 3:
fatal("bad archive");
break;
case 4:
fatal("system error in tar");
break;
default:
fatal("tar exited with nozero status: %d", ws.w_retcode);
break;
}
(void) close(archivefd);
return;
}
/*
*----------------------------------------------------------------------
*
* readTapeLabel --
*
* Read the label on a tape, and put the label into the tapeBuffer.
*
* Results:
* None
*
* Side effects:
* The tape is rewound.
*
*----------------------------------------------------------------------
*/
static void
readTapeLabel()
{
ReturnStatus status = SUCCESS;
int n;
int bytesRead;
Dev_TapeStatus tapeStatus;
debugp((stderr, "reading tape label\n"));
labelSize = LABEL_SIZE_OLD;
bzero((char *) &tapeStatus, sizeof(tapeStatus));
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
if ((status != SUCCESS) || (tapeStatus.type == DEV_TAPE_EXB8200) ||
(reInitialize) || (reInitializeSafe)) {
/*
* The tape may be in the old format if the tape drive is an
* exb8200, or if we are reinitializing an old format tape.
* Try reading the label at the beginning of the tape.
*/
rewindTape();
bytesRead = read(archivefd, tapeBuffer, labelSize);
debugp((stderr, "attempt to read old label read %d bytes\n",
bytesRead));
if (bytesRead == labelSize) {
if (!strncmp(tapeBuffer, SPRITE_OLD_DUMP_HEADER,
strlen(SPRITE_OLD_DUMP_HEADER)) != 0) {
oldFormat = TRUE;
debugp((stderr, "Using old format\n"));
n = sscanf(tapeBuffer + strlen(SPRITE_OLD_DUMP_HEADER),
"%d", &tapeNumber);
if (n != 1) {
warning("Couldn't read tape number from label\n");
}
} else if (oldFormat) {
fatal("The tape does not have a correct label");
}
}
}
if (!oldFormat) {
Boolean beginning = FALSE;
labelSize = LABEL_SIZE;
gotoEOD();
/*
* Keep backing up one file at a time until we find a label, or
* the beginning of the tape. In order to back up one file at
* a time we must back up over both the current file and the
* previous file, hence the skip backwards over two files.
*
*/
status = SUCCESS;
while(status == SUCCESS) {
status = skipFiles(-2);
if (status == DEV_END_OF_TAPE) {
/*
* We must have hit the beginning of the tape.
* Keep track so we only do this once.
*/
debugp((stderr, "hit beginning of tape\n"));
if (beginning == TRUE) {
fatal("The tape does not have a correct label");
}
beginning = TRUE;
status = SUCCESS;
} else if (status == SUCCESS) {
/*
* We are now on the BOT side of a file mark. Skip to the
* EOT side.
*/
debugp((stderr, "skipping over file mark\n"));
status = skipFiles(1);
if (status != SUCCESS) {
fatal("Error skipping over file mark");
}
}
/*
* Try reading the label.
*/
debugp((stderr, "trying to read label (%d bytes)\n",
labelSize));
bytesRead = read(archivefd, tapeBuffer, labelSize);
if (bytesRead == labelSize) {
debugp((stderr, "read succeeded\n"));
if (!strncmp(tapeBuffer, SPRITE_DUMP_HEADER,
strlen(SPRITE_DUMP_HEADER))){
/*
* We found a label.
*/
debugp((stderr, "found a label\n"));
break;
} else {
debugp((stderr, "found \"%s\"\n", tapeBuffer));
}
} else {
debugp((stderr, "only read %d bytes\n", bytesRead));
}
}
if (status != SUCCESS) {
fatal("The tape does not have a correct label");
}
n = sscanf(tapeBuffer + strlen(SPRITE_DUMP_HEADER),
"%*s %d %*s %d %*s %d\n", &version, &tapeLevel,
&tapeNumber);
if (n != 3) {
fatal("Couldn't read information from tape label\n");
}
if (version != SPRITE_DUMP_VERSION) {
fatal("Invalid dump tape version \"%d\"\n", version);
}
}
debugp((stderr, "Tape: %d\n", tapeNumber));
debugp((stderr, "Version: %d\n", version));
debugp((stderr, "Level: %d\n", tapeLevel));
debugp((stderr, "TapeLabel=|%s|\n", tapeBuffer));
return;
}
#ifdef PROG_DUMP
/*
*----------------------------------------------------------------------
*
* writeTapeLabel --
*
* Copy the tapeBuffer onto the tape.
*
* Results:
* None
*
* Side effects:
* The tape is rewound.
*
*----------------------------------------------------------------------
*/
static void
writeTapeLabel()
{
debugp((stderr, "writing tape label\n"));
if (oldFormat) {
rewindTape();
} else {
gotoEOD();
}
if (write(archivefd, tapeBuffer, labelSize) != labelSize) {
fatal("Error writing tape label");
}
/*
* Rewinding the tape prevents a file mark from being written, which
* is what we want on the old format tapes.
*/
if (oldFormat) {
rewindTape();
}
return;
}
#endif
static void
initializeTape()
{
int nbufs;
FILE *fp;
Dev_TapeStatus tapeStatus;
int tocSize;
static char tempBuffer[IOBUF_SIZE];
ReturnStatus status;
debugp((stderr, "initializing tape #%d\n", tapeNumber));
if (archiveFileIsATapeDrive == 0) {
fatal("Cannot initialize: Archive file is not a tape drive");
}
rewindTape();
bzero((char *) &tapeStatus, sizeof(tapeStatus));
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
if ((status != SUCCESS) || (tapeStatus.type == DEV_TAPE_EXB8200)) {
oldFormat = TRUE;
labelSize = LABEL_SIZE_OLD;
} else {
oldFormat = FALSE;
labelSize = LABEL_SIZE;
}
memset(tapeBuffer, '\0', labelSize);
if (oldFormat) {
sprintf(tapeBuffer, "%s%d\n", SPRITE_OLD_DUMP_HEADER, tapeNumber);
} else {
char format[80];
strcpy(format, SPRITE_DUMP_HEADER);
strcat(format, SPRITE_DUMP_INFO);
sprintf(tapeBuffer, format, SPRITE_DUMP_VERSION, tapeLevel,tapeNumber);
strcat(tapeBuffer, "\n");
}
debugp((stderr, "writing label\n"));
if (write(archivefd, tapeBuffer, labelSize) != labelSize) {
fatal("Write error while initializing tape label");
}
debugp((stderr, "done writing label\n"));
if (oldFormat) {
tocSize = TOC_SIZE_OLD;
} else {
tocSize = TOC_SIZE;
}
debugp((stderr, "writing padding\n"));
memset(tempBuffer, '\0', sizeof(tempBuffer));
for (nbufs = tocSize / IOBUF_SIZE; --nbufs > 0;) {
if (write(archivefd, tempBuffer,
sizeof(tempBuffer)) != sizeof(tempBuffer)) {
fatal("Write error while initializing tape label");
}
}
debugp((stderr, "done writing padding\n"));
if (!oldFormat) {
Dev_TapeCommand args;
args.command = IOC_TAPE_WEOF;
args.count = 1;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(Address)&args, 0, (Address) 0);
if (status != SUCCESS) {
fatal("Can't write file mark(s), status = 0x%x", status);
exit(status);
}
}
rewindTape();
if (official) {
if ((fp = fopen(DUMPDATES, "a")) == NULL) {
fatal("Can't open %s", DUMPDATES);
}
/*
* Put a comment in the dump data file.
*/
fprintf(fp, "# Initializing tape number %03d\n", tapeNumber);
(void) fclose(fp);
}
return;
}
static void
rewindTape()
{
int oldOffset;
int status;
debugp((stderr, "rewinding tape ...\n"));
status = Ioc_Reposition(archivefd, IOC_BASE_ZERO, 0, &oldOffset);
if (status != SUCCESS) {
fatal("Can't rewind tape drive, status = 0x%08x", status);
}
debugp((stderr, "done rewinding tape.\n"));
return;
}
static void
setFileNumber()
{
char *s;
#ifdef PROG_DUMP
fileNumber = 1;
for (s = tapeBuffer; *s != '\0'; ++s) {
if (s[0] == '\n' && s[1] > ' ') {
++fileNumber;
}
}
#else
char *end;
int len = 0;
int n = 1;
/*
* Check each file on the dumptape, and pick the one that is the
* longest prefix of the file to be restored.
*/
if ((end = strchr(tapeBuffer, '\n')) == NULL) {
fatal("Bad tape label\n");
}
for (s = end; *s != '\0'; ++n) {
s = end + 1;
if ((end = strchr(s, '\n')) == NULL) {
break;
}
*end = '\0';
if (parseDumpInfo(s) == 0) {
fatal("format error in tapelabel, line %d\n", n);
}
assert(dumpDateEntry.file == n);
lastFile = n;
if (strlen(dumpDateEntry.dirname) >= len) {
if (strncmp(dumpDateEntry.dirname, progArgv[1],
strlen(dumpDateEntry.dirname)) == 0) {
len = strlen(dumpDateEntry.dirname);
fileNumber = n;
}
#if 0
else if (dumpDateEntry.dirname[0] == '/') {
if (strncmp(dumpDateEntry.dirname + 1, progArgv[1],
strlen(dumpDateEntry.dirname) - 1) == 0) {
len = strlen(dumpDateEntry.dirname) - 1;
fileNumber = n;
}
}
#endif
}
}
(void) fprintf(stderr, "Using file #%d\n", fileNumber);
if (fileNumber == 0) {
fatal("None of the files on this tape contain %s.\n", progArgv[1]);
}
#endif
return;
}
#ifdef PROG_RESTORE
static void
findLastFile()
{
char *s;
int n = 1;
char *end;
if ((end = strchr(tapeBuffer, '\n')) == NULL) {
fatal("Bad tape label\n");
}
for (s = end; *s != '\0'; ++n) {
s = end + 1;
if ((end = strchr(s, '\n')) == NULL) {
break;
}
*end = '\0';
lastFile = n;
}
}
#endif /* PROG_RESTORE */
static void
skipOverFiles()
{
int status;
int num;
#ifdef PROG_DUMP
Dev_TapeCommand args;
#endif
assert(fileNumber);
if (oldFormat) {
rewindTape();
num = fileNumber;
} else {
/*
* In the new format we don't rewind the tape. Instead we back
* up from where we currently are to the file we want.
*/
num = - (lastFile - fileNumber + 1) * 2;
}
status = skipFiles(num);
if (status != SUCCESS) {
fatal("Can't skip files, status = 0x%08x", status);
}
#ifdef PROG_DUMP
if (oldFormat) {
debugp((stderr, "Backing up over filemark\n"));
status = skipFiles(-1);
if (status != SUCCESS) {
fatal("Can't skip files, status = 0x%08x", status);
}
}
debugp((stderr, "rewriting file mark\n"));
args.command = IOC_TAPE_WEOF;
args.count = 1;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, (char *) 0);
#else
if (!oldFormat) {
/*
* Since we backed up we are on the BOT side of a file mark.
* Skip over it.
*/
debugp((stderr, "Skipping over filemark\n"));
status = skipFiles(1);
if (status != SUCCESS) {
fatal("Can't skip files, status = 0x%08x", status);
}
}
#endif
debugp((stderr, "successfully skipped %d files\n", fileNumber));
return;
}
/*ARGSUSED*/
static void
cleanup_sighup(sig)
int sig;
{
fatal("Received SIGHUP signal, terminating abnormally");
return;
}
/*ARGSUSED*/
static void
cleanup_sigint(sig)
int sig;
{
fatal("Received SIGINT signal, terminating abnormally");
return;
}
/*ARGSUSED*/
static void
cleanup_sigquit(sig)
int sig;
{
fatal("Received SIGQUIT signal, terminating abnormally");
return;
}
/*ARGSUSED*/
static void
cleanup_sigpipe(sig)
int sig;
{
#if 1
{
int w;
union wait ws;
debugp((stderr, "Received SIGPIPE signal, terminating abnormally\n"));
while ((w = wait(&ws)) > 0 && w != tarChild) {
continue;
}
debugp((stderr, "SIGPIPE: tar exited with code = 0x%x\n", ws.w_retcode));
if (ws.w_retcode) {
warning("tar exited with nozero status: %d", ws.w_retcode);
++fatalErrors;
}
(void) close(archivefd);
}
#endif
fatal("Received SIGPIPE signal, terminating abnormally");
return;
}
/*ARGSUSED*/
static void
cleanup_sigterm(sig)
int sig;
{
fatal("Received SIGTERM signal, terminating abnormally");
return;
}
/*
*----------------------------------------------------------------------
*
* sendMail --
*
* Results:
* None.
*
* Side effects:
* Sends mail to the person specified by the -m option.
*
*----------------------------------------------------------------------
*/
static void
sendMail(msg)
const char *msg;
{
int p[2];
int childPid;
int w;
FILE *fp;
if (mailWho == NULL) {
return;
}
pipe(p);
fprintf(stderr, "sending mail to `%s'\n", mailWho);
switch (childPid = fork()) {
case -1:
fatal("Fork failed");
case 0: /* child */
close(pipefd[1]);
dup2(pipefd[0], 0);
execlp("mail", "mail", mailWho, NULL);
fatal("Can't exec `mail'");
/* NOTREACHED */
default: /* parent */
close(pipefd[0]);
fp = fdopen(pipefd[1], "w");
fprintf(fp, "%s.\n\n", msg);
fprintf(fp, "Level %d dump of %s on %s",
dumpLevel, directoryToDump,
asctime(localtime(&startTime)));
(void) fclose(fp);
while ((w = wait(0)) > 0 && w != childPid)
;
fprintf(stderr, "done sending mail\n");
break;
}
return;
}
/*
*----------------------------------------------------------------------
*
* fatal --
*
* Print an error message and terminate the program.
*
* Results:
* None.
*
* Side effects:
* A formated error message is printed to stderr, and
* the program is terminated.
*
*----------------------------------------------------------------------
*/
#ifndef lint
static void
fatal(va_alist)
va_dcl
{
char *errmsg;
va_list args;
char mailBuf[0x1000];
char *fmt;
errmsg = strerror(errno);
va_start(args);
fmt = va_arg(args, char *);
(void) fprintf(stderr, "Dump: ");
(void) vfprintf(stderr, fmt, args);
(void) fprintf(stderr, ": %s\n", errmsg);
(void) fflush(stderr);
(void) vsprintf(mailBuf, fmt, args);
(void) strcat(mailBuf, ": ");
(void) strcat(mailBuf, errmsg);
sendMail(mailBuf);
va_end(args);
exit(1);
}
#else
/*VARARGS1*/
/*ARGSUSED*/
void
fatal(fmt)
char *fmt;
{
return;
}
#endif /* !lint */
/*
*----------------------------------------------------------------------
*
* warning --
*
* Print a warning message.
*
* Results:
* None.
*
* Side effects:
* A formated error message is printed to stderr.
*
*----------------------------------------------------------------------
*/
#ifndef lint
static void
warning(va_alist)
va_dcl
{
const char *errmsg;
va_list args;
char *fmt;
errmsg = strerror(errno);
va_start(args);
fmt = va_arg(args, char *);
(void) fprintf(stderr, "Dump: ");
(void) vfprintf(stderr, fmt, args);
(void) fprintf(stderr, ": %s\n", errmsg);
(void) fflush(stderr);
va_end(args);
return;
}
#else
/*VARARGS1*/
/*ARGSUSED*/
void
warning(fmt)
char *fmt;
{
return;
}
#endif /* !lint */
/*
*----------------------------------------------------------------------
*
* openLog --
*
* Open the dump log file and tee stderr so that all
* error messages are appended to the log.
*
* Results:
* None.
*
* Side effects:
* The log file is opened, and stderr is redirected to it.
*
*----------------------------------------------------------------------
*/
static void
openLog()
{
int pfd[2];
char buf[BUFSIZ];
int fd;
pipe(pfd);
switch (fork()) {
case -1:
fatal("fork failed");
/* NOTREACHED */
case 0: /* child */
close(pfd[1]);
if ((fd = open(LOGFILE, O_APPEND | O_WRONLY | O_CREAT, 0666)) < 0) {
warning("Can't open log file %s", LOGFILE);
return;
}
for (;;) {
int r;
switch (r = read(pfd[0], buf, sizeof(buf))) {
case -1:
fatal("Error reading from pipe");
/* NOTREACHED */
case 0:
close(fd);
exit(0);
default:
write(2, buf, r);
if (write(fd, buf, r) != r) {
warning("Error writing to %s", LOGFILE);
}
continue;
}
}
/* NOTREACHED */
default: /* parent */
close(pfd[0]);
dup2(pfd[1], 2); /* write all errors to log */
break;
}
return;
}
/*
*----------------------------------------------------------------------
*
* quote_string --
*
* Expand all control characters in a string to the equivalent
* backslashed excape sequence. For instance, a tab is converted
* to the two characters '\' and 't'.
*
* Results:
* None.
*
* Side effects:
* Modified the destination string.
*
*----------------------------------------------------------------------
*/
static void
quote_string(to, from)
char *to;
const char *from;
{
int c;
for (;;) {
switch (c = *from++) {
case '\0':
*to = '\0';
return;
case '\\':
*to++ = '\\';
*to++ = '\\';
break;
case '\n':
*to++ = '\\';
*to++ = 'n';
break;
case '\t':
*to++= '\\';
*to++= 't';
break;
case '\f':
*to++= '\\';
*to++= 'f';
break;
case '\b':
*to++= '\\';
*to++= 'b';
break;
default:
if (c < 0x20) {
*to++ = '\\';
*to++ = '0' + ((c >> 3) & 7);
*to++ = '0' + (c & 7);
break;
} else {
*to++ = c;
}
}
}
}
/*
*----------------------------------------------------------------------
*
* checkTape --
*
* Check the dumpdates file to make sure it is safe to initialize
* the tape. We do this by grepping through the last 100 lines
* of the dumpdates file to see if the tape has been used.
*
* Results:
* None.
*
* Side effects:
* Will exit with failure if it is not safe.
*
*----------------------------------------------------------------------
*/
static void
checkTape()
{
char buf[1000];
int status;
sprintf(buf,"tail -100 %s | grep \"^%3.3d\" > /dev/null", DUMPDATES,
tapeNumber);
status = system(buf);
if (status==0) {
fprintf(stderr,"dump: tape %d recently used; init failed\n",
tapeNumber);
} else if (status==256 || status==1) {
return;
} else {
fprintf(stderr,"dump: unable to do dumpdates safety check\n");
}
exit(123);
}
/*
*----------------------------------------------------------------------
*
* gotoEOD --
*
* Move tape to end-of-data.
*
* Results:
* None.
*
* Side effects:
* The tape is moved.
*
*----------------------------------------------------------------------
*/
static void
gotoEOD()
{
Dev_TapeCommand args;
ReturnStatus status;
int files;
debugp((stderr, "skipping to end of data\n"));
args.command = IOC_TAPE_SKIP_EOD;
args.count = 0;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, NULL);
if (status != SUCCESS) {
warning("Skip to end of data returned 0x%x", status);
/*
* If we are doing a restore then we want to do our best to
* find the end of usable data. Otherwise we return an error.
*/
fprintf(stderr, "Trying to find last file on tape\n");
files = 0;
rewindTape();
/*
* Skip over initial label.
*/
status = skipFiles(1);
if (status == SUCCESS) {
files++;
/*
* Now skip over pairs of dump files and labels.
*/
while(1) {
status = skipFiles(2);
if (status != SUCCESS) {
break;
}
files += 2;
}
}
fprintf(stderr, "Tape ends with file %d\n", files);
rewindTape();
status = skipFiles(files);
if (status != SUCCESS) {
fatal("Can't find end of tape");
}
}
}
/*
*----------------------------------------------------------------------
*
* skipFiles --
*
* Skip the given number of files.
*
* Results:
* Return status from the ioctl.
*
* Side effects:
* The tape is moved around.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
skipFiles(num)
int num; /* Number of files to skip. */
{
ReturnStatus status;
Dev_TapeCommand args;
debugp((stderr, "skipping %d files\n", num));
args.command = IOC_TAPE_SKIP_FILES;
args.count = num;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, (char *) 0);
return status;
}
@
1.11
log
@Change files from /sprite/admin/dump/foo.new to /sprite/admin/dump/foo.
(Mike checking in for John.)
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.10 91/11/22 15:02:14 jhh Exp Locker: jhh $";
d112 1
d114 1
d165 1
d167 1
d199 1
d201 1
d321 1
a321 1
#else
d333 1
a333 1
#endif
d443 1
a443 1
FILE *fp;
d926 1
a926 1
strcat(tarargs, "ncfTP");
d930 1
a930 1
strcat(tarargs, "ncbfTP");
d1399 1
d1419 1
d1426 1
d1428 1
a1900 3
Dev_TapeStatus tapeStatus;
int remaining;
int position;
@
1.10
log
@if eod can't be found then rewind the tape, and skip over files until
it fails, then rewind the tape again and skip to the last good file.
This is the right thing to do for restore, and if the dumps died,
and if there is a media error
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.9 91/11/22 14:09:03 jhh Exp Locker: jhh $";
d60 3
a62 3
#define DUMPDATES "/sprite/admin/dump/dumpdates.new"
#define LOGFILE "/sprite/admin/dump/dumplog.new"
#define DRIVELOG "/sprite/admin/dump/statuslog.new"
@
1.9
log
@added -T option
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.8 91/10/11 11:57:18 jhh Exp Locker: jhh $";
d1894 1
a1902 1
#ifdef PROG_RESTORE
d1908 19
a1926 5
fprintf(stderr, "Trying to skip to just before error\n");
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
if (status != SUCCESS) {
fatal("Can't find the end of data");
d1928 1
a1928 2
remaining = tapeStatus.remaining;
debugp((stderr, "remaining = %d\n", remaining));
d1930 1
a1930 2
status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL,
sizeof(tapeStatus), &tapeStatus);
d1932 1
a1932 1
fatal("Can't find the end of data");
a1933 15
debugp((stderr, "remaining = %d\n", tapeStatus.remaining));
position = tapeStatus.remaining - remaining - 50000;
debugp((stderr, "block = %d\n", position));
if (position > 0) {
args.command = IOC_TAPE_GOTO_BLOCK;
args.count = position;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, NULL);
if (status != SUCCESS) {
fatal("Can't skip to block %d", position);
}
}
#else
fatal("Skip to end of data returned 0x%x", status);
#endif
@
1.8
log
@added -u option, findLastFile
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump.new/RCS/main.c,v 1.7 91/09/10 11:16:59 jhh Exp $";
d112 1
d141 1
d951 5
d957 1
a957 1
strcpy(tarargs, "xpf");
d959 1
a959 1
strcpy(tarargs, "xpfb");
@
1.7
log
@added new dump format
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.5 91/06/05 15:06:58 mgbaker Exp Locker: shirriff $";
d101 2
a102 2
static int reInitialize;
static int reInitializeSafe;
d111 1
d127 1
d161 1
d194 2
d203 9
a235 1
startTime = time(0L);
d317 2
d450 4
a453 2
if ((fp = fopen(DUMPDATES, "a")) == NULL) {
fatal("Can't open %s", DUMPDATES);
d481 1
a481 1
(void) sprintf(buf, "%03d %02d %d %6.1lf %6.1lf %s %s\n",
d484 11
a494 2
fprintf(fp, "%s", buf);
(void) fclose(fp);
a528 4
if (archiveFileIsATapeDrive) {
strcat(tapeBuffer, buf);
writeTapeLabel();
}
d1286 21
a1306 2
if ((fp = fopen(DUMPDATES, "a")) == NULL) {
fatal("Can't open %s", DUMPDATES);
a1307 5
/*
* Put a comment in the dump data file.
*/
fprintf(fp, "# Initializing tape number %03d\n", tapeNumber);
(void) fclose(fp);
d1387 20
d1880 1
a1880 1
gotoEOD(VOID)
d1884 3
d1888 1
d1895 35
a1929 1
fatal("Can't skip to end of data");
@
1.6
log
@Added checkTape function to ensure a recent tape doesn't get
accidentally initialized.
@
text
@d39 2
a40 3
#ifdef __STDC__
#include <stdarg.h>
#else
a41 1
#endif
d43 3
d47 1
a47 2
extern int errno;
extern int open();
d49 1
d51 3
a53 4
#define SPRITE_DUMP_HEADER "SPRITE DUMP TAPE #"
#define DUMPDATES "/sprite/admin/dump/dumpdates"
#define LOGFILE "/sprite/admin/dump/dumplog"
d55 9
a63 1
#define TAR "tar.gnu"
d67 1
a68 2
#define TOC_SIZE MBytes(10) /* TOC occupied 10 MB on the tape */
#define TOC_USEABLE MBytes(2) /* About 2 MB of it can be used */
d70 11
d86 1
a86 1
static int dumpLevel;
d88 1
a90 1
static long startTime;
d105 6
d141 36
a176 30
static void cleanup_sighup(void);
static void cleanup_sigint(void);
static void cleanup_sigquit(void);
static void cleanup_sigpipe(void);
static void cleanup_sigterm(void);
static void openArchiveFile(void);
static void forkOffTar(void);
static void dumpDirectory(const char *dir);
static void initializeTape(void);
static void sendMail(const char *msg);
static void rewindTape(void);
static void fatal(const char *fmt, ...);
static void warning(const char *fmt, ...);
static void readTapeLabel(void);
static void rewindTape(void);
static void openLog(void);
static void skipOverFiles(void);
static void waitForChildToDie(void);
static void setFileNumber(void);
static void quote_string(char *to, const char *from);
static void checkTape(void);
static int parseDumpInfo(char *buf);
#ifdef PROG_DUMP
static int getNextDumpDateEntry(void);
static void writeTapeLabel(void);
static void flushOutput(void);
static void getDumpDate(void);
static void recordTime(void);
d190 1
d198 1
a198 1
argc = Opt_Parse(argc, argv, OptionArray, Opt_Number(OptionArray));
d217 5
d227 1
a237 1
rewindTape();
d269 12
a280 1
skipOverFiles();
d298 2
d309 1
a310 3
rewindTape();
debugp((stderr, "finished dumping %s, %ld bytes\n",
directoryToDump, totalBytes));
d338 1
a338 1
const char *dir;
d391 3
a393 1
int nbytes;
d420 14
a433 3
FILE *fp;
char buf[0x1000];
char *date;
d440 27
a466 3
(void) sprintf(buf, "%03d %02d %d %10d %s %s\n",
tapeNumber, fileNumber, dumpLevel, totalBytes,
date, directoryToDump);
d469 34
d573 1
a573 1
static char const months[][4] = {
d580 2
d583 1
d588 1
a588 2
debugp((stderr, "parseDumpInfo: mismatch on first token\n"));
return 0;
d591 1
a591 1
d596 1
a596 2
debugp((stderr, "parseDumpInfo: mismatch on second token\n"));
return 0;
d599 1
d607 1
a607 2
debugp((stderr, "parseDumpInfo: mismatch on third token\n"));
return 0;
d610 1
d614 20
a633 2
dumpDateEntry.nbytes = atoi(s);
d641 1
a641 2
debugp((stderr, "parseDumpInfo: mismatch on fifth token\n"));
return 0;
d643 1
d645 1
a645 2
debugp((stderr, "parseDumpInfo: mismatch on sixth token\n"));
return 0;
d647 1
d654 1
a654 2
debugp((stderr, "parseDumpInfo: mismatch on month\n"));
return 0;
d657 1
a657 2
debugp((stderr, "parseDumpInfo: mismatch on date\n"));
return 0;
d659 1
d662 1
a662 2
debugp((stderr, "parseDumpInfo: mismatch on hour\n"));
return 0;
d664 1
d667 1
a667 2
debugp((stderr, "parseDumpInfo: mismatch on minute\n"));
return 0;
d669 1
d672 1
a672 2
debugp((stderr, "parseDumpInfo: mismatch on seconds\n"));
return 0;
d674 1
d677 1
a677 2
debugp((stderr, "parseDumpInfo: mismatch on year\n"));
return 0;
d686 1
d688 1
a688 2
debugp((stderr, "parseDumpInfo: mismatch on last token\n"));
return 0;
d696 5
d763 2
d797 22
d847 20
a866 2
char tarargs[20];
d895 10
a904 3
strcat(tarargs, "ncfTP");
debugp((stderr, "execing tar %s - -\n", tarargs));
execlp(TAR, TAR, tarargs, "-", "-", NULL);
a913 2
char **arg;
int i;
d915 1
d922 10
a931 4
case 0:
arg = (char **) malloc(sizeof(char **) * (progArgc + 4));
arg[0] = TAR;
strcpy(tarargs, "xpf");
d941 6
a946 3
arg[1] = tarargs;
arg[2] = archiveFileName;
for (i = 1; (arg[2 + i] = progArgv[i]) != NULL; ++i) {
d949 5
d956 1
a956 1
d1052 4
d1058 30
a1087 3
rewindTape();
if (read(archivefd, tapeBuffer, sizeof(tapeBuffer)) != sizeof(tapeBuffer)) {
fatal("Error reading tape label");
d1089 71
a1159 3
if (strncmp(tapeBuffer,
SPRITE_DUMP_HEADER, strlen(SPRITE_DUMP_HEADER)) != 0) {
fatal("The tape does not have a correct label");
d1161 3
a1163 2
tapeNumber= atoi(tapeBuffer + strlen(SPRITE_DUMP_HEADER));
debugp((stderr, "Using tape #%d\n", tapeNumber));
d1172 1
a1172 1
* readTapeLabel --
d1190 6
a1195 3
rewindTape();
if (write(archivefd, tapeBuffer,
sizeof(tapeBuffer)) != sizeof(tapeBuffer)) {
d1198 7
a1204 1
rewindTape();
d1214 4
d1224 23
a1246 4
memset(tapeBuffer, '\0', sizeof(tapeBuffer));
sprintf(tapeBuffer, "%s%d\n", SPRITE_DUMP_HEADER, tapeNumber);
if (write(archivefd, tapeBuffer,
sizeof(tapeBuffer)) != sizeof(tapeBuffer)) {
d1249 11
a1259 4
memset(tapeBuffer, '\0', sizeof(tapeBuffer));
for (nbufs = TOC_SIZE / IOBUF_SIZE; --nbufs > 0;) {
if (write(archivefd, tapeBuffer,
sizeof(tapeBuffer)) != sizeof(tapeBuffer)) {
d1263 1
d1324 2
a1325 1
if (strlen(dumpDateEntry.dirname) > len) {
d1353 3
a1355 2
Dev_TapeCommand args;
int status;
a1356 1
debugp((stderr, "skipping %d files\n", fileNumber));
d1358 11
a1368 5
rewindTape();
args.command = IOC_TAPE_SKIP_FILES;
args.count = fileNumber;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, (char *) 0);
d1373 7
a1379 4
debugp((stderr, "Backing up one file\n"));
args.count = -1;
status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
(char *) &args, 0, (char *) 0);
d1385 12
d1402 1
d1404 2
a1405 1
cleanup_sighup(void)
d1412 1
d1414 2
a1415 1
cleanup_sigint(void)
d1422 1
d1424 2
a1425 1
cleanup_sigquit(void)
d1432 1
d1434 2
a1435 1
cleanup_sigpipe(void)
d1460 1
d1462 2
a1463 1
cleanup_sigterm(void)
a1545 1
#ifdef __STDC__
d1547 1
a1547 4
fatal(const char *fmt, ...)
#else
void
fatal(fmt, va_alist)
a1548 1
#endif
d1550 1
a1550 1
const char *errmsg;
d1553 1
a1555 3
#ifdef __STDC__
va_start(args, fmt);
#else
d1557 1
a1557 1
#endif
d1600 2
a1601 6
#ifdef __STDC__
void
warning(const char *fmt, ...)
#else
void
warning(fmt, va_alist)
a1602 1
#endif
d1606 1
a1608 3
#ifdef __STDC__
va_start(args, fmt);
#else
d1610 1
a1610 1
#endif
d1805 63
@
1.5
log
@Made dump program operate under userid "dumper", so dump effects
can be removed from traces of system performance.
(checked in by shirriff)
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.4 91/05/10 17:00:37 mgbaker Exp Locker: mgbaker $";
d84 1
d99 1
d138 1
d203 4
a206 1
if (reInitialize) {
d1408 37
@
1.4
log
@Mary checking this in for Bob.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.3 90/11/15 01:21:03 rab Exp Locker: rab $";
d29 1
d151 6
d158 1
d167 16
@
1.3
log
@Improved error messages.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.2 90/10/07 15:10:39 rab Exp Locker: rab $";
d229 1
d231 1
@
1.2
log
@Fixed to handle backslash in filename. Also some other bug fixes.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.1 90/09/07 11:47:34 rab Exp Locker: rab $";
d51 2
a52 2
#define DUMPDATES "/sprite/admin/dump/new-dumpdates"
#define LOGFILE "/sprite/admin/dump/new-dumplog"
d76 2
a77 1
static int errors;
a81 1
static int relativePaths;
d91 1
a91 1
{ OPT_TRUE, "d", (char *) &debug, "Debug" },
d103 1
d106 1
a106 1
{ OPT_TRUE, "d", (char *) &debug, "Debug" },
a122 1
static int getNextDumpDateEntry(void);
a128 1
static void writeTapeLabel(void);
d134 1
a135 1
static void quote_string(char *to, const char *from);
d138 2
d211 2
a212 2
if (errors) {
sendMail("Dump completed with non-fatal errors.");
d214 5
a218 1
sendMail("Dump completed successfully.");
d232 4
a235 2
debugp((stderr, "%s exiting, there were %d errors\n", argv[0], errors));
exit(errors);
d269 1
a269 1
++errors;
d285 1
a285 1
++errors;
d292 1
a292 1
++errors;
d308 10
a359 9
static struct {
int tape;
int file;
int level;
int nbytes;
time_t time;
char dirname[MAXPATHLEN];
} dumpDateEntry;
d416 1
a416 1
d530 2
d566 1
d730 1
d757 1
d768 25
a792 3
if (ws.w_retcode) {
warning("tar exited with nozero status: %d", ws.w_retcode);
++errors;
d833 1
d863 1
d1045 1
a1045 1
++errors;
@
1.1
log
@Initial revision
@
text
@d18 1
a18 1
static char rcsid[] = "$Header$";
d84 1
a85 1
d91 1
d105 1
d136 1
d255 1
d281 1
d283 1
a283 1
if (puts(pathname) == EOF) {
d287 1
a287 1
fprintf(stderr, "%s\n", pathname);
d392 5
a396 1
if (((s = strtok(buf, " \t\n")) == NULL) || *s == '\0' || *s == '#') {
d400 2
a401 2
fatal("format error in %s: line %d, char %d",
DUMPDATES, lineCnt, s - buf);
d427 1
d436 1
d447 1
d463 1
d467 1
d476 1
d480 1
d485 1
d490 1
d495 1
d500 1
d506 1
d511 1
d615 2
a616 1
fatal("%s: not a normal file or tape drive", archiveFileName);
d663 6
d700 3
d881 1
a881 2
char *s, *end;
d890 1
d902 1
a902 1
for (; *s != '\0'; ++n) {
d913 2
a914 2
if (strncmp(dumpDateEntry.dirname,
progArgv[1], strlen(dumpDateEntry.dirname)) == 0) {
d918 9
d995 18
d1267 72
@